using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace Speedball2 {
  public static class Field {

    public static Bitmap Build () {
      if (SpriteManager.Version == VersionEnum.Atari)
        return (BuildAtari ());
      else if (SpriteManager.Version == VersionEnum.Amiga)
        return (BuildAmiga ());
      else
        throw new Exception ();
    }

    public static Bitmap BuildAtari () {
      List<Bitmap> fieldBitmaps = SpriteManager.GetBank (BankEnum.PitchDat);
      Bitmap topBorder = fieldBitmaps [9];
      int wallLeftIndex = SpriteManager.WallLeftIndex;
      int wallRightIndex = SpriteManager.WallRightIndex;
      //List<Bitmap> wallLeft = BankManager.Banks [0x549EA].GetBitmaps ();
      //List<Bitmap> wallRight = BankManager.Banks [0x565EA].GetBitmaps ();

      Bitmap field = new Bitmap (20 * 32, 36 * 32);
      Graphics g = Graphics.FromImage (field);
      // BORDER
      // top
      DrawTileAtari (g, topBorder, 0, 0);
      // left
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 0], 0, 1);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 1], 0, 2);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 3);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 3], 0, 4);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 5);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 3], 0, 6);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 7);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 3], 0, 8);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 9);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 3], 0, 10);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 4], 0, 11);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 5], 0, 12);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 5], 0, 13);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 5], 0, 14);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 5], 0, 15);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 5], 0, 16);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 17);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 10], 0, 18);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 11], 1, 18);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 12], 0, 19);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 13], 1, 19);
      fieldBitmaps [wallLeftIndex + 0].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallLeftIndex + 1].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallLeftIndex + 2].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallLeftIndex + 3].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallLeftIndex + 4].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallLeftIndex + 8].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallLeftIndex + 9].RotateFlip (RotateFlipType.RotateNoneFlipY);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 20);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 3], 0, 21);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 22);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 3], 0, 23);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 4], 0, 24);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 3], 0, 25);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 26);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 8], 0, 27);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 28);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 3], 0, 29);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 30);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 3], 0, 31);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 2], 0, 32);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 1], 0, 33);
      DrawTileAtari (g, fieldBitmaps [wallLeftIndex + 0], 0, 34);
      // bottom
      topBorder.RotateFlip (RotateFlipType.RotateNoneFlipY);
      DrawTileAtari (g, topBorder, 0, 35);
      // right
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 0], 19, 1);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 1], 19, 2);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 3);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 3], 19, 4);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 5);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 3], 19, 6);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 7);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 8], 19, 8);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 9);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 3], 19, 10);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 4], 19, 11);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 3], 19, 12);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 13);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 3], 19, 14);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 15);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 10], 18, 16);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 11], 19, 16);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 12], 18, 17);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 13], 19, 17);
      fieldBitmaps [wallRightIndex + 0].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallRightIndex + 1].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallRightIndex + 2].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallRightIndex + 3].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallRightIndex + 4].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallRightIndex + 5].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallRightIndex + 6].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [wallRightIndex + 7].RotateFlip (RotateFlipType.RotateNoneFlipY);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 18);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 5], 19, 19);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 5], 19, 20);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 5], 19, 21);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 5], 19, 22);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 5], 19, 23);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 4], 19, 24);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 3], 19, 25);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 26);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 3], 19, 27);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 28);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 3], 19, 29);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 30);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 3], 19, 31);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 2], 19, 32);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 1], 19, 33);
      DrawTileAtari (g, fieldBitmaps [wallRightIndex + 0], 19, 34);

      // TERRAIN
      //top
      DrawTileAtari (g, fieldBitmaps [0], 1, 1);
      for (int i = 0; i < 8; i++) {
        DrawTileAtari (g, fieldBitmaps [1], 2 + i * 2, 1);
        DrawTileAtari (g, fieldBitmaps [2], 3 + i * 2, 1);
      }
      DrawTileAtari (g, fieldBitmaps [3], 18, 1);
      // left
      for (int i = 0; i < 16; i++)
        DrawTileAtari (g, fieldBitmaps [7], 1, 2 + i);
      for (int i = 0; i < 14; i++)
        DrawTileAtari (g, fieldBitmaps [7], 1, 20 + i);
      // right
      for (int i = 0; i < 14; i++)
        DrawTileAtari (g, fieldBitmaps [8], 18, 2 + i);
      for (int i = 0; i < 16; i++)
        DrawTileAtari (g, fieldBitmaps [8], 18, 18 + i);
      // bottom
      fieldBitmaps [0].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [1].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [2].RotateFlip (RotateFlipType.RotateNoneFlipY);
      fieldBitmaps [3].RotateFlip (RotateFlipType.RotateNoneFlipY);
      DrawTileAtari (g, fieldBitmaps [0], 1, 34);
      for (int i = 0; i < 8; i++) {
        DrawTileAtari (g, fieldBitmaps [1], 2 + i * 2, 34);
        DrawTileAtari (g, fieldBitmaps [2], 3 + i * 2, 34);
      }
      DrawTileAtari (g, fieldBitmaps [3], 18, 34);
      // small squares
      for (int i = 0; i < 16; i++) {
        for (int j = 0; j < 2; j++)
          DrawTileAtari (g, fieldBitmaps [4], 2 + i, 6 + j);
        for (int j = 0; j < 4; j++)
          DrawTileAtari (g, fieldBitmaps [4], 2 + i, 16 + j);
        for (int j = 0; j < 2; j++)
          DrawTileAtari (g, fieldBitmaps [4], 2 + i, 28 + j);
      }
      // big squares
      Bitmap middleLeft = fieldBitmaps [5].ExtractBitmap (0, 15, 32, 2);
      Bitmap middleRight = fieldBitmaps [6].ExtractBitmap (0, 15, 32, 2);
      for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 2; j++)
          DrawBigSquareAtari (g, fieldBitmaps [5], fieldBitmaps [6], middleLeft, middleRight, 2 + i * 2, 2 + j * 2);
        for (int j = 0; j < 4; j++)
          DrawBigSquareAtari (g, fieldBitmaps [5], fieldBitmaps [6], middleLeft, middleRight, 2 + i * 2, 8 + j * 2);
        for (int j = 0; j < 4; j++)
          DrawBigSquareAtari (g, fieldBitmaps [5], fieldBitmaps [6], middleLeft, middleRight, 2 + i * 2, 20 + j * 2);
        for (int j = 0; j < 2; j++)
          DrawBigSquareAtari (g, fieldBitmaps [5], fieldBitmaps [6], middleLeft, middleRight, 2 + i * 2, 30 + j * 2);
      }
      // hack for bottom
      Bitmap topLeft = fieldBitmaps [5].ExtractBitmap (0, 0, 32, 1);
      Bitmap topRight = fieldBitmaps [6].ExtractBitmap (0, 0, 32, 1);
      for (int i = 0; i < 8; i++) {
        DrawTileAtari (g, topLeft, 2 + i * 2, 34);
        DrawTileAtari (g, topRight, 3 + i * 2, 34);
      }

      //field.Save ("toto.png", System.Drawing.Imaging.ImageFormat.Png);
      return (field);
    }

    public static Bitmap BuildAmiga () {
      List<Bitmap> fieldBitmaps = SpriteManager.GetBank (BankEnum.PitchDat);

      //Bitmap topBorder = fieldBitmaps [9];
      //int wallLeftIndex = SpriteManager.WallLeftIndex;
      //int wallRightIndex = SpriteManager.WallRightIndex;

      Bitmap field = new Bitmap (40 * 16, 72 * 16);
      Graphics g = Graphics.FromImage (field);

      byte [] pitchMap = SpriteManager.GetBankBytes ("pitch.map");

      Dictionary<int, Bitmap> mirrored = new Dictionary<int, Bitmap> ();
      g.Clear (Color.Red);
      for (int y = 0; y < 72; y++)
        for (int x = 0; x < 40; x++) {
          int cell = pitchMap.ReadWordSigned ((y * 40 + x) * 2);
          if (cell == 0)
            cell = 162;
          if ((cell >= 1) && (cell <= fieldBitmaps.Count))
            DrawTileAmiga (g, fieldBitmaps [cell - 1], x, y);
          else {
            cell = -cell;
            if (!mirrored.ContainsKey (cell - 1)) {
              Bitmap bitmap = (Bitmap) fieldBitmaps [cell - 1].Clone ();
              bitmap.RotateFlip (RotateFlipType.RotateNoneFlipY);
              mirrored.Add (cell - 1, bitmap);
            }
            DrawTileAmiga (g, mirrored [cell - 1], x, y);
          }
          //Console.WriteLine (string.Format ("{0:X} {0}", cell + 0));
          //g.DrawStringOutlinedCentered ((cell + 0).ToString (), Game.Font, Brushes.White, Brushes.Black, x * 16 + 8, y * 16 + 8);
          //if ((x % 2) == 0)
          //  g.DrawStringOutlinedCentered (string.Format ("{0:X}", (y * 40 + x) * 2), Game.Font, Brushes.White, Brushes.Black, x * 16 + 8, y * 16 + 8);
        }
      //field.Save ("field.png", ImageFormat.Png);
      //Environment.Exit (0);
      return (field);
    }

    private static void DrawTileAtari (Graphics g, Bitmap bitmap, int x, int y) {
      g.DrawImage (bitmap, x * 32, y * 32);
    }

    private static void DrawTileAmiga (Graphics g, Bitmap bitmap, int x, int y) {
      g.DrawImage (bitmap, x * 16, y * 16);
    }

    private static void DrawBigSquareAtari (Graphics g, Bitmap bitmapSquareLeft, Bitmap bitmapSquareRight, Bitmap bitmapMiddleLeft, Bitmap bitmapMiddleRight, int x, int y) {
      DrawTileAtari (g, bitmapSquareLeft, x, y);
      DrawTileAtari (g, bitmapSquareRight, x + 1, y);
      DrawTileAtari (g, bitmapSquareLeft, x, y + 1);
      DrawTileAtari (g, bitmapSquareRight, x + 1, y + 1);
      g.DrawImage (bitmapMiddleLeft, x * 32, ((y + 1) * 32) - 1);
      g.DrawImage (bitmapMiddleRight, (x + 1) * 32, ((y + 1) * 32) - 1);
    }
  }
}
